/**
 * OwnLSASlot.java
 *
 * @author Hagen Boehm
 */


package SSF.OS.OSPFv2;


import SSF.OS.ProtocolException;
import SSF.Net.Util.IP_s;

// ============================= class SSF.OS.OSPFv2.OwnLSASlot ================================= //
/**
 *  This class extends LSASlot. It implements two additional timer to guarantee first periodic
 *  originations of new instances of the LSA, stored here at the moment, and second protection
 *  of too many recreations of the LSA. Only selforiginated LSAs can be stored here! It is further 
 *  assumed, that every time a new instance is installed it is also originated.
 */
public class OwnLSASlot extends LSASlot {

  // ............................ member data ..................................... //
  /** boolean value which indicates write-protection of the stored LSA. */
  private boolean isProtected;

  /** boolean value indicating that a new instance of the stored LSA could not be installed
   *  cause of minLSInstTimer and therefore should be created and installed after expiration
   *  of the Timer.
   */
  private boolean createNewInstance;

  /** boolean value indicating that the LSA stored in this slot has entered the sequence
   *  number wrapping process. A new instance of the LSA will be neither created nor installed
   *  until this boolean is unset.
   */
  private boolean lsaIsWrapping;

  /** The sequence number for the next instance of the selforiginated LSA stored in this slot. */
  public int nextSeqNum;

  /** long value indicating duration of the MinimumIntervalTimer. */
  public long minLSInterval;

  /** long value indicating duration of the LSRefreshTimer. */
  public long lsRefreshTime;

  /** A link to the Area this Slot belongs to. */
  public AreaData myArea;

  // ............................... OwnLSASlot Timers ........................................ //
  /** After expiration of this timer a new instance of the stored LSA can be installed. */
  public MinimumIntervalTimer minLSInstTimer;

  /** After expiration of this timer a new instance of the stored LSA should be originated. */
  public LSRefreshTimer lsRefreshTimer;

  // ------------------------------- constructor OwnLSASlot ----------------------------------- //
  public OwnLSASlot(LSA lsa, OSPF myOSPF, AreaData myArea) {
    super(lsa, myOSPF);
    this.myArea = myArea;
    this.minLSInterval = myOSPF.MIN_LS_ITVL;
    this.lsRefreshTime = myOSPF.LS_REFRESH_TIME;
    isProtected = true;
    createNewInstance = false;
    lsaIsWrapping = false;
    nextSeqNum = lsa.lsSeqnum + 1;
    minLSInstTimer = new MinimumIntervalTimer(myOSPF, minLSInterval);
    lsRefreshTimer = new LSRefreshTimer(myOSPF, lsRefreshTime);
    minLSInstTimer.set(minLSInterval);
    lsRefreshTimer.set(lsRefreshTime);
  }

  // -------------------------------- OwnLSASlot.install -------------------------------------- //
  /** installs a new instance of an existing LSA in this slot. */
  public void install(LSA adv) throws ProtocolException {
    if (lsaIsWrapping) {
      throw new ProtocolException("Could not install new instance of LSA \"" + adv.getKey() + 
                                  "\"! (sequence number wrapping)");
    }
    if (lsa.lsAge == myOSPF.MAX_AGE) {
      throw new ProtocolException("Could not install new instance of LSA \"" + adv.getKey() + 
                                  "\"! (LSA is being flushed from routing domain)");
    }
    if (isProtected) {
      createNewInstance = true;
      throw new ProtocolException("Could not install new instance of LSA \"" + adv.getKey() + 
                                  "\"! (MinLSInterval)");
    }
    super.install(adv);
    isProtected = true;
    if (nextSeqNum == myOSPF.MAX_SEQUENCE_NUM + 1) lsaIsWrapping = true;
    else nextSeqNum++;
    minLSInstTimer = new MinimumIntervalTimer(myOSPF, minLSInterval);
    if (lsRefreshTimer != null) lsRefreshTimer.cancel();
    lsRefreshTimer = new LSRefreshTimer(myOSPF, lsRefreshTime);
    minLSInstTimer.set(minLSInterval);
    lsRefreshTimer.set(lsRefreshTime);
  }

  // ----------------------------- OwnLSASlot.lsaIsProtected ---------------------------------- //
  /** Check whether installation of the LSA stored here was at least MIN_LS_ITVL seconds ago.
   *  @return the value of isProtected.
   */
  public boolean lsaIsProtected() {
    return isProtected;
  }

  // =========================== inner class LSRefreshTimer ============================== //
  /**
  /* The LSRefreshTimer waits OSPF LS_REFRESH_TIME time before it declares the LSA stored here
   * to be outdated. Next time the LSA is aged by the Area Data Structure, a new instance should
   * be originated.
   */
  
  public class LSRefreshTimer extends SSF.OS.Timer {
    
    // -------------------------- constructor LSRefreshTimer ----------------------------- //

    public LSRefreshTimer(OSPF o, long dt) {
      super(o.inGraph(), dt);
    }

    // -------------------------- LSRefreshTimer.callback -------------------------------- //
    public void callback() {
      LSA sumLSA;
      int summaryCost;
      switch (lsa.lsType) {
        case LSA.ROUTER_LSA:
          myArea.createRouterLSA();
	break;
        case LSA.SUMMARY_NETWORK_LSA:
	  Summary_LSA body = (Summary_LSA)lsa.payload();
          String summaryDest = lsa.lsID + "/" + body.netMask;
          summaryCost = myOSPF.routingTable.getNetCost(summaryDest, myArea.areaID);
          if (summaryCost != -1) {
	    sumLSA = myArea.createSummary3LSA(lsa.lsID, body.netMask, summaryCost);
            myArea.installSelfOrigLSA(sumLSA);
          } else {
            sumLSA = myArea.createSummary3LSA(lsa.lsID, body.netMask, body.metric);
            sumLSA.lsAge = OSPF.MAX_AGE;
            myArea.installSelfOrigLSA(sumLSA);
          }
          myArea.databaseDebugInfo();
	break;
        case LSA.SUMMARY_ASBR_LSA:
          summaryCost = myOSPF.routingTable.getRoutCost(new Integer(lsa.lsID), myArea.areaID);
          if (summaryCost != -1) {
	    sumLSA = myArea.createSummary4LSA(lsa.lsID, summaryCost);
            myArea.installSelfOrigLSA(sumLSA);
          } else {
	    sumLSA = myArea.createSummary4LSA(lsa.lsID, ((Summary_LSA)lsa.payload()).metric);
            sumLSA.lsAge = OSPF.MAX_AGE;
            myArea.installSelfOrigLSA(sumLSA);
          }
          myArea.databaseDebugInfo();
	break;
      }
    }

  } // end of class LSRefreshTimer


  // =========================== inner class MinimumIntervalTimer ============================== //
  /**
  /* The MinimumIntervalTimer waits minLSInterval seconds before it cancels the write-protection
   * for the LSA stored in the Slot. A new instance of the LSA will be created and installed if 
   * "createNewLSA" is set. This can only be done after minLSInterval.
   */
  
  public class MinimumIntervalTimer extends SSF.OS.Timer {

    // ------------------------- constructor MinimumIntervalTimer ------------------------------ //

    public MinimumIntervalTimer(OSPF o, long dt) {
      super(o.inGraph(), dt);
    }

    // -------------------------- MinimumIntervalTimer.callback -------------------------------- //
    public void callback() {
      LSA sumLSA;
      int summaryCost;
      isProtected = false;
      if (createNewInstance) {
        createNewInstance = false;
        switch (lsa.lsType) {
        case LSA.ROUTER_LSA:
          myArea.createRouterLSA();
	break;
        case LSA.SUMMARY_NETWORK_LSA:
          Summary_LSA body = (Summary_LSA)lsa.payload();
          String summaryDest = lsa.lsID + "/" + body.netMask;
          summaryCost = myOSPF.routingTable.getNetCost(summaryDest, myArea.areaID);
          if (summaryCost != -1) {
	    sumLSA = myArea.createSummary3LSA(lsa.lsID, body.netMask, summaryCost);
            myArea.installSelfOrigLSA(sumLSA);
          } else {
            sumLSA = myArea.createSummary3LSA(lsa.lsID, body.netMask, body.metric);
            sumLSA.lsAge = OSPF.MAX_AGE;
            myArea.installSelfOrigLSA(sumLSA);
          }
          myArea.databaseDebugInfo();
	break;
        case LSA.SUMMARY_ASBR_LSA:
          summaryCost = myOSPF.routingTable.getRoutCost(new Integer(lsa.lsID), myArea.areaID);
          if (summaryCost != -1) {
	    sumLSA = myArea.createSummary4LSA(lsa.lsID, summaryCost);
            myArea.installSelfOrigLSA(sumLSA);
          } else {
	    sumLSA = myArea.createSummary4LSA(lsa.lsID, ((Summary_LSA)lsa.payload()).metric);
            sumLSA.lsAge = OSPF.MAX_AGE;
            myArea.installSelfOrigLSA(sumLSA);
          }
          myArea.databaseDebugInfo();
	break;
        }
      }
    }

  } // end of class MinimumIntervalTimer

} // end of class OwnLSASlot





















